#Instalación rSFFreader
# source("http://bioconductor.org/biocLite.R")
# biocLite("rSFFreader")
require(rSFFreader)
library(gdata)
library(reshape2)
library(plotly)
library(ggplot2)
library(Biostrings)
#source("https://bioconductor.org/biocLite.R")
#biocLite("R453Plus1Toolbox")
library(R453Plus1Toolbox)
samples<-grep(".sff",list.files("./samples"),value=TRUE)

Ejemplo de libro

#ejemplo de libro
sff<- load454SampleData()
Total number of reads to be read: 1000
reading header for sff file:/home/sergio/R/x86_64-pc-linux-gnu-library/3.3/rSFFreader/extdata/Small454Test.sff
reading file:/home/sergio/R/x86_64-pc-linux-gnu-library/3.3/rSFFreader/extdata/Small454Test.sff
##Generate some QA plots:
##Read length histograms:
par(mfrow=c(2,2))
clipMode(sff) <- "raw"
hist(width(sff),breaks=500,col="grey",xlab="Read Length",main="Raw Read Length")
## Base by position plots:
clipMode(sff) <- "raw"
ac <- alphabetByCycle(sread(sff),alphabet=c("A","C","T","G","N"))
ac.reads <- apply(ac,2,sum)
acf <- sweep(ac,MARGIN=2,FUN="/",STATS=apply(ac,2,sum))
matplot(cbind(t(acf),ac.reads/ac.reads[1]),col=c("green","blue","black","red","darkgrey","purple"),
        type="l",lty=1,xlab="Base Position",ylab="Base Frequency",
        main="Base by position")
cols <- c("green","blue","black","red","darkgrey","purple")
leg <- c("A","C","T","G","N","%reads")
legend("topright", col=cols, legend=leg, pch=18, cex=.8)
clipMode(sff) <- "full"
hist(width(sff),breaks=500,col="grey",xlab="Read Length",main="Clipped Read Length")
ac <- alphabetByCycle(sread(sff),alphabet=c("A","C","T","G","N"))
ac.reads <- apply(ac,2,sum)
acf <- sweep(ac,MARGIN=2,FUN="/",STATS=apply(ac,2,sum))
matplot(cbind(t(acf),ac.reads/ac.reads[1]),col=c("green","blue","black","red","darkgrey","purple"),
        type="l",lty=1,xlab="Base Position",ylab="Base Frequency",
        main="Base by position")
legend("topright", col=cols, legend=leg, pch=18, cex=.8)

IMPORT DATA

SIN CLIP - RAW DATA ANALYSIS

lenStat_raw<-vector()
lenStat_qual<-vector()
nucFreq_raw<-matrix(nrow=1000, ncol=1)
nucFreq_qual<-matrix(nrow=1000, ncol=1)
count_raw<-data.frame()
count_qual<-data.frame()
len_raw<-list()
len_qual<-list()
for(i in samples){
  sff<-readSff(paste("samples/",i,sep=""), use.qualities=TRUE, use.names=TRUE,clipMode = c("raw"), verbose=TRUE)
##Generate some QA plots:
  ##Read length histograms (with and without clipping):
  
  # RAW
  par(mfrow=c(2,2))
  clipMode(sff) <- "raw"
  hist(width(sff),breaks=500,col="grey",xlab="Read Length",
       xlim= c(50,800), main= "RAW read length")
  lenStat_raw<-rbind(lenStat_raw, c(gsub("454Reads.MID_","",gsub(".sff","",i)), summary(width(sff)) ) )
  count_raw[i,1]<-length(sff)
  len_raw[[i]]<-width(sff)
    ## Base by position plots:
  ac <- alphabetByCycle(sread(sff),alphabet=c("A","C","T","G","N"))
  ac.reads <- apply(ac,2,sum)
  acf <- sweep(ac,MARGIN=2,FUN="/",STATS=apply(ac,2,sum))
  tacf<-t(acf); colnames(tacf)<-paste(gsub("454Reads.MID_","",gsub(".sff","",i)),"_",  c("A","C","T","G","N"),sep="")
  nucFreq_raw<-cbindX(nucFreq_raw,tacf)
  matplot(cbind(t(acf),ac.reads/ac.reads[1]),col=c("green","blue","black","red","darkgrey","purple"),
        type="l",lty=1,xlab="Base Position",ylab="Base Frequency",
        main="Base by position", xlim=c(0,1500))
  cols <- c("green","blue","black","red","darkgrey","purple")
  leg <- c("A","C","T","G","N","%reads")
  legend("topright", col=cols, legend=leg, pch=18, cex=.8)
  
  ### FILTER QUALITY
  clipMode(sff) <- "full"
  hist(width(sff),breaks=500,col="grey",xlab="Read Length",
       xlim= c(50,800),main="CLIPPED read length" )
  lenStat_qual<-rbind(lenStat_qual,c(gsub("454Reads.MID_","",gsub(".sff","",i)), summary(width(sff)) ) )
  count_qual[i,1]<-length(sff)
  len_qual[[i]]<-width(sff)
  ## Base by position plots:
  ac <- alphabetByCycle(sread(sff),alphabet=c("A","C","T","G","N"))
  ac.reads <- apply(ac,2,sum)
  acf <- sweep(ac,MARGIN=2,FUN="/",STATS=apply(ac,2,sum))
    tacf<-t(acf); colnames(tacf)<-paste(gsub("454Reads.MID_","",gsub(".sff","",i)),"_",  c("A","C","T","G","N"),sep="")
  nucFreq_qual<-cbindX(nucFreq_qual,tacf)
  matplot(cbind(t(acf),ac.reads/ac.reads[1]),col=c("green","blue","black","red","darkgrey","purple"),
        type="l",lty=1,xlab="Base Position",ylab="Base Frequency",
        main="Base by position", xlim=c(0,1000))
  par(mfrow=c(1,1))
  legend("topright", col=cols, legend=leg, pch=18, cex=.8)
  title(paste("sample: ",gsub("454Reads.MID_","",gsub(".sff","",i)),sep=""))
  dev.copy(png,filename=paste("Explo_",gsub("454Reads.MID_","",gsub(".sff","",i)),".png",sep=""));
  dev.off ();
}
Total number of reads to be read: 2233
reading header for sff file:samples/454Reads.MID_s01_rs3.sff
reading file:samples/454Reads.MID_s01_rs3.sff
Total number of reads to be read: 2405
reading header for sff file:samples/454Reads.MID_s02_rs3.sff
reading file:samples/454Reads.MID_s02_rs3.sff

Total number of reads to be read: 2054
reading header for sff file:samples/454Reads.MID_s03_rs5.sff
reading file:samples/454Reads.MID_s03_rs5.sff

Total number of reads to be read: 11821
reading header for sff file:samples/454Reads.MID_s04_rl3.sff
reading file:samples/454Reads.MID_s04_rl3.sff

Total number of reads to be read: 10580
reading header for sff file:samples/454Reads.MID_s05_rl3.sff
reading file:samples/454Reads.MID_s05_rl3.sff

Total number of reads to be read: 8869
reading header for sff file:samples/454Reads.MID_s06_rl5.sff
reading file:samples/454Reads.MID_s06_rl5.sff

Total number of reads to be read: 9255
reading header for sff file:samples/454Reads.MID_s07_dl3.sff
reading file:samples/454Reads.MID_s07_dl3.sff

Total number of reads to be read: 9579
reading header for sff file:samples/454Reads.MID_s08_dl3.sff
reading file:samples/454Reads.MID_s08_dl3.sff

Total number of reads to be read: 9987
reading header for sff file:samples/454Reads.MID_s09_dl5.sff
reading file:samples/454Reads.MID_s09_dl5.sff

EstadĆ­sticas de las lecturas

#Statistics about lenght
as.data.frame(lenStat_raw)
write.csv(as.data.frame(lenStat_raw), "Raw_Readlength_stats.csv",row.names = FALSE )
as.data.frame(lenStat_qual)
write.csv(as.data.frame(lenStat_qual), "Clip_Readlength_stats.csv",row.names = FALSE )
#Nucleotide frequency by position
write.csv(nucFreq_raw, "Raw_NuclFreqByPos.csv",row.names = FALSE )
write.csv(nucFreq_qual, "Clip_NuclFreqByPos.csv",row.names = FALSE )
#All length data by sample
count_raw$sample<-gsub("454Reads.MID_","",gsub(".sff","",rownames(count_raw)))
count_qual$sample<-gsub("454Reads.MID_","",gsub(".sff","",rownames(count_qual)))
length_raw<-do.call(cbindX, lapply(len_raw, as.data.frame))
colnames(length_raw)<-gsub("454Reads.MID_","",gsub(".sff","",rownames(count_raw)))
length_qual<-do.call(cbindX, lapply(len_qual, as.data.frame))
colnames(length_qual)<-gsub("454Reads.MID_","",gsub(".sff","",rownames(count_qual)))
rownames(count_raw)<-NULL;rownames(count_qual)<-NULL
write.csv(length_raw, "Raw_AllReadlength.csv",row.names = FALSE )
write.csv(length_qual, "Clip_AllReadlength.csv",row.names = FALSE )
#AMount of sequences by sample
count_raw
write.csv(count_raw, "Raw_CountBySample.csv",row.names = FALSE )
count_qual
write.csv(count_qual, "Clip_CountBySample.csv",row.names = FALSE )
#GRAFICO DE BARRAS CON LA CANTIDAD DE LECTURAS
#plot(cantidad$cantidad, type="b")
library(ggplot2)
p<-ggplot(count_raw, aes(x=sample, weight=V1))+ geom_bar(fill="#2b8cbe")+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))
ggplotly(p)
#GRAFICO DE CAJAS
#boxplot(longitud)
p<-ggplot(data = melt(length_raw), aes(x=variable, y=value)) + geom_boxplot(aes(fill=variable))+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+ ggtitle("Raw Reads")
ggplotly(p)
#GRAFICO DE CAJAS
#boxplot(longitud)
p<-ggplot(data = melt(length_qual), aes(x=variable, y=value)) + geom_boxplot(aes(fill=variable))+
  theme(axis.text.x = element_text(angle = 45, hjust = 1))+ ggtitle("Clipped Reads")
ggplotly(p)
for(i in samples){
  sff<-readSff(paste("samples/",i,sep=""), use.qualities=TRUE, use.names=TRUE,clipMode = c("raw"), verbose=TRUE)
customClip(sff) <- IRanges(start = 1, end = 15)
clipMode(sff) <- "custom"
print("distinct MIDs at 5'")
print(length(table(counts=as.character(sread(sff)))))
print("More frequents")
print(sort(table(counts=as.character(sread(sff))), decreasing=TRUE))
}
Total number of reads to be read: 2233
reading header for sff file:samples/454Reads.MID_s01_rs3.sff
reading file:samples/454Reads.MID_s01_rs3.sff
[1] "distinct MIDs at 5'"
[1] 3
[1] "More frequents"
counts
TCAGTGTACTACTCC TCAGTGTACTACTCT TCAGTGTACTACTCA 
           2224               5               4 
Total number of reads to be read: 2405
reading header for sff file:samples/454Reads.MID_s02_rs3.sff
reading file:samples/454Reads.MID_s02_rs3.sff
[1] "distinct MIDs at 5'"
[1] 4
[1] "More frequents"
counts
TCAGACGACTACAGC TCAGACGACTACAGT TCAGACGACTACAGG TCAGACGACTACAGA 
           2396               4               3               2 
Total number of reads to be read: 2054
reading header for sff file:samples/454Reads.MID_s03_rs5.sff
reading file:samples/454Reads.MID_s03_rs5.sff
[1] "distinct MIDs at 5'"
[1] 2
[1] "More frequents"
counts
TCAGAGCACTGTAGC TCAGAGCACTGTAGT 
           2053               1 
Total number of reads to be read: 11821
reading header for sff file:samples/454Reads.MID_s04_rl3.sff
reading file:samples/454Reads.MID_s04_rl3.sff
[1] "distinct MIDs at 5'"
[1] 3
[1] "More frequents"
counts
TCAGCACACGATAGC TCAGCACACGATAGA TCAGCACACGATAGT 
          11794              20               7 
Total number of reads to be read: 10580
reading header for sff file:samples/454Reads.MID_s05_rl3.sff
reading file:samples/454Reads.MID_s05_rl3.sff
[1] "distinct MIDs at 5'"
[1] 4
[1] "More frequents"
counts
TCAGCACTCGCACGC TCAGCACTCGCACGA TCAGCACTCGCACGT TCAGCACTCGCACGG 
          10559              12               7               2 
Total number of reads to be read: 8869
reading header for sff file:samples/454Reads.MID_s06_rl5.sff
reading file:samples/454Reads.MID_s06_rl5.sff
[1] "distinct MIDs at 5'"
[1] 3
[1] "More frequents"
counts
TCAGCAGACGTCTGC TCAGCAGACGTCTGA TCAGCAGACGTCTGT 
           8853              12               4 
Total number of reads to be read: 9255
reading header for sff file:samples/454Reads.MID_s07_dl3.sff
reading file:samples/454Reads.MID_s07_dl3.sff
[1] "distinct MIDs at 5'"
[1] 3
[1] "More frequents"
counts
TCAGATCGTCTGTGC TCAGATCGTCTGTGA TCAGATCGTCTGTGT 
           9228              18               9 
Total number of reads to be read: 9579
reading header for sff file:samples/454Reads.MID_s08_dl3.sff
reading file:samples/454Reads.MID_s08_dl3.sff
[1] "distinct MIDs at 5'"
[1] 4
[1] "More frequents"
counts
TCAGATGTACGATGC TCAGATGTACGATGA TCAGATGTACGATGT TCAGATGTACGATGG 
           9562              11               5               1 
Total number of reads to be read: 9987
reading header for sff file:samples/454Reads.MID_s09_dl5.sff
reading file:samples/454Reads.MID_s09_dl5.sff
[1] "distinct MIDs at 5'"
[1] 4
[1] "More frequents"
counts
TCAGATGTGTCTAGC TCAGATGTGTCTAGA TCAGATGTGTCTAGT TCAGATGTGTCTAGG 
           9969              13               4               1 

Explore Each seque

quantile(as(readFullQ, "numeric"))
  0%  25%  50%  75% 100% 
   0   11   13   25   40 
readsRaw<-sread(sff)
readsRawQ<-   as(quality(sff), "PhredQuality")  
library(ShortRead); setSR <- ShortReadQ(sread=readsRaw, quality=FastqQuality(BStringSet(readsRawQ)), BStringSet(readsRawQ))
myMA <- as(quality(setSR), "matrix")

Processed with SSFinfo

file_name<-gsub("454Reads.MID_","",gsub(".sff","",i))
library(Biostrings)
pro1_read = readDNAStringSet(paste("samples/processed_files/",file_name,"/",file_name,".fna", sep=""), format="fasta")
pro1_read_width<-as.data.frame(cbind(names(pro1_read),width(pro1_read)))
head(pro1_read_width)
sffContainer <- readSFF(paste("samples/",i,sep=""))
Reading file 454Reads.MID_s01_rs3.sff ... done! 
showClass("SFFContainer")
Class "SFFContainer" [package "R453Plus1Toolbox"]

Slots:
                                                                                    
Name:                       name            flowgramFormat                 flowChars
Class:                 character                   numeric                 character
                                                                                    
Name:                keySequence           clipQualityLeft          clipQualityRight
Class:                 character                   numeric                   numeric
                                                                                    
Name:            clipAdapterLeft          clipAdapterRight                 flowgrams
Class:                   numeric                   numeric                      list
                                                          
Name:                flowIndexes                     reads
Class:                      list QualityScaledDNAStringSet
reads(sffContainer)
  A QualityScaledDNAStringSet instance containing:

  A DNAStringSet instance of length 2233
       width seq                                                                      names               
   [1]   684 TCAGTGTACTACTCCACGACGTTTGTAAACGACGC...TACGTTAGGGTAAACGGAACCGGACGGAAACGGG H3C8HXX01ATG0S
   [2]   552 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...AACAAGCATATTGACGCTGGGAAAGGACCACGAG H3C8HXX01BDS7I
   [3]   546 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...CAAAAACAGCATATGACGCTGGGAAGACCGAGAG H3C8HXX01ANWA5
   [4]   769 TCAGTGTACTACTCCACGACGTTTGTAAACGACGC...AAAACGGGAAACCCGGTAACGGGAAGGGAAACCG H3C8HXX01A3BQX
   [5]   564 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...AAGAACATATATACGTCNCGGAAGAACCGAAGAG H3C8HXX01AMUIH
   ...   ... ...
[2229]   580 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...ANTTTAGCGTACTGGGTAAAAGGACCCTAGACGG H3C8HXX01AQGHL
[2230]   700 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...AGGACCTACGGGTAAAGGAAACCGTACCGGGACG H3C8HXX01BBPGN
[2231]   616 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...GGTAACCGNGTTGGGAAAACGGACCGTAGAACGG H3C8HXX01AR5XF
[2232]   802 TCAGTGTACTACTCCACGACGTTTGTAAAACGACG...CGACCGGGTTAAAAGGACCCGGGTAAAGTACCGG H3C8HXX01BBAJR
[2233]   566 TCAGTGTACTACTCCACGACGTTGTAAAACGAACG...AATTGTACGATTCCGGGGAAAGGAAACCGACGAG H3C8HXX01A1VEZ

  A PhredQuality instance of length 2233
       width seq                                                                      names               
   [1]   684 FFFFFFFFFFFFFFFIIIIIIHHHIIHHHIIIIII...,.0..,,,,,,,,.0,,,,,,,,,,,,...,,,, H3C8HXX01ATG0S
   [2]   552 FFFFFFFFFFFFFFFIIIIHHDDDFE::::EFFHH...,,,)),003111444..,,,,,,,,,,,,,,0.. H3C8HXX01BDS7I
   [3]   546 IIIIIIIIIIIIIIIIIIIIIHHHIICCCAIIFII...(,-//.4+1121//115/,,,,,,,,.,,,,,// H3C8HXX01ANWA5
   [4]   769 FFFFFFFFFFFFFFFIIIIIIHHHIIHHHIIIIIH...,,,,.*))))).,,,,,,,,,,,,,,,-//2770 H3C8HXX01A3BQX
   [5]   564 FFFFFFFFFFFFFFFIIIIIIHFHHH;:::FFFFF...))6002.,,,,13,,,,!,,,,,,,,,,....,, H3C8HXX01AMUIH
   ...   ... ...
[2229]   580 FFFFCCCFFDDDDDDEFFHHIHD@BB@@AAFD<::...,!,,,,,,,,,,,0,,,,,,,,,),,,,.0,,,, H3C8HXX01AQGHL
[2230]   700 FFFFFFFFD@@@FFFHHFFFGFCCCA;;;;::4=A...,,,,,00,,,,0./..,,,,030,,,,,,,,,,, H3C8HXX01BBPGN
[2231]   616 DD?:::ADDFFFFFFFFFFGFF??DA;;999?6?<...00.,,,,.!,,,,,/..,,,,,),,20,,,,,,, H3C8HXX01AR5XF
[2232]   802 FFFFFFFFFFDDFAAAAA:::;88822222//-//....3444/,,,,,,,,,,),,,,,,,,,.-4-,,,, H3C8HXX01BBAJR
[2233]   566 DFFCCCC???FDDAA?AAB=555544464?=55=?...,,,,,,04.---882222444---,,,,,,,,,, H3C8HXX01A1VEZ
#qualityReportSFF(sffContainer, "report.pdf")
positionQualityBoxplot(sffContainer)

#dinucleotideOddsRatio
#sff2fastq()
#Example flowgram
seqtab<-cbindX(as.data.frame(sffContainer@flowgrams$H3C8HXX01ATG0S),
as.data.frame(sffContainer@flowIndexes$H3C8HXX01ATG0S),
as.data.frame(sffContainer@reads$H3C8HXX01ATG0S),
as.data.frame(sffContainer@reads@quality$H3C8HXX01ATG0S),
as.data.frame(as.numeric(sffContainer@reads@quality$H3C8HXX01ATG0S)) )
colnames(seqtab)<-c("flowgrams","flowIndexes","basecall","quality_char","quality_value")
seqtab%>%
  group_by(basecall)%>%
        plot_ly( y = ~quality_value, color = ~basecall, type = "box")
seqtab%>%
  group_by(basecall)%>%
        plot_ly( y = ~flowgrams, color = ~basecall, type = "box")
  
     
#sffContainer@clipQualityLeft
#sffContainer@clipQualityRight


###
#convert http://www.drive5.com/usearch/manual/quality_score.html
#http://gatkforums.broadinstitute.org/gatk/discussion/4260/phred-scaled-quality-scores

#as.numeric(sffContainer@reads@quality$H3C8HXX01ATG0S)
#### Hacer una  vector para cada secuencia con todas las frecuencias de 4 nucleótidos

reads = sread(sff)
nf = oligonucleotideFrequency(reads, width=4)
#hclust(dist(nf)) # do hierarchical clustering of your tetra freq.
LS0tCnRpdGxlOiAiVGVzaXMiCm91dHB1dDoKICBodG1sX2RvY3VtZW50OiBkZWZhdWx0CiAgaHRtbF9ub3RlYm9vazoKICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgZmlnX2hlaWdodDogMTUKICAgIGZpZ193aWR0aDogMTUKLS0tCgoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojSW5zdGFsYWNpw7NuIHJTRkZyZWFkZXIKIyBzb3VyY2UoImh0dHA6Ly9iaW9jb25kdWN0b3Iub3JnL2Jpb2NMaXRlLlIiKQojIGJpb2NMaXRlKCJyU0ZGcmVhZGVyIikKcmVxdWlyZShyU0ZGcmVhZGVyKQpsaWJyYXJ5KGdkYXRhKQpsaWJyYXJ5KHJlc2hhcGUyKQpsaWJyYXJ5KHBsb3RseSkKbGlicmFyeShnZ3Bsb3QyKQpsaWJyYXJ5KEJpb3N0cmluZ3MpCgoKI3NvdXJjZSgiaHR0cHM6Ly9iaW9jb25kdWN0b3Iub3JnL2Jpb2NMaXRlLlIiKQojYmlvY0xpdGUoIlI0NTNQbHVzMVRvb2xib3giKQpsaWJyYXJ5KFI0NTNQbHVzMVRvb2xib3gpCgoKc2FtcGxlczwtZ3JlcCgiLnNmZiIsbGlzdC5maWxlcygiLi9zYW1wbGVzIiksdmFsdWU9VFJVRSkKYGBgCgojIyMgRWplbXBsbyBkZSBsaWJybwpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2VqZW1wbG8gZGUgbGlicm8KIyBzZmY8LSBsb2FkNDU0U2FtcGxlRGF0YSgpCiMgIyNHZW5lcmF0ZSBzb21lIFFBIHBsb3RzOgojICMjUmVhZCBsZW5ndGggaGlzdG9ncmFtczoKIyBwYXIobWZyb3c9YygyLDIpKQojIGNsaXBNb2RlKHNmZikgPC0gInJhdyIKIyBoaXN0KHdpZHRoKHNmZiksYnJlYWtzPTUwMCxjb2w9ImdyZXkiLHhsYWI9IlJlYWQgTGVuZ3RoIixtYWluPSJSYXcgUmVhZCBMZW5ndGgiKQojICMjIEJhc2UgYnkgcG9zaXRpb24gcGxvdHM6CiMgY2xpcE1vZGUoc2ZmKSA8LSAicmF3IgojIGFjIDwtIGFscGhhYmV0QnlDeWNsZShzcmVhZChzZmYpLGFscGhhYmV0PWMoIkEiLCJDIiwiVCIsIkciLCJOIikpCiMgYWMucmVhZHMgPC0gYXBwbHkoYWMsMixzdW0pCiMgYWNmIDwtIHN3ZWVwKGFjLE1BUkdJTj0yLEZVTj0iLyIsU1RBVFM9YXBwbHkoYWMsMixzdW0pKQojIG1hdHBsb3QoY2JpbmQodChhY2YpLGFjLnJlYWRzL2FjLnJlYWRzWzFdKSxjb2w9YygiZ3JlZW4iLCJibHVlIiwiYmxhY2siLCJyZWQiLCJkYXJrZ3JleSIsInB1cnBsZSIpLAojICAgICAgICAgdHlwZT0ibCIsbHR5PTEseGxhYj0iQmFzZSBQb3NpdGlvbiIseWxhYj0iQmFzZSBGcmVxdWVuY3kiLAojICAgICAgICAgbWFpbj0iQmFzZSBieSBwb3NpdGlvbiIpCiMgY29scyA8LSBjKCJncmVlbiIsImJsdWUiLCJibGFjayIsInJlZCIsImRhcmtncmV5IiwicHVycGxlIikKIyBsZWcgPC0gYygiQSIsIkMiLCJUIiwiRyIsIk4iLCIlcmVhZHMiKQojIGxlZ2VuZCgidG9wcmlnaHQiLCBjb2w9Y29scywgbGVnZW5kPWxlZywgcGNoPTE4LCBjZXg9LjgpCiMgY2xpcE1vZGUoc2ZmKSA8LSAiZnVsbCIKIyBoaXN0KHdpZHRoKHNmZiksYnJlYWtzPTUwMCxjb2w9ImdyZXkiLHhsYWI9IlJlYWQgTGVuZ3RoIixtYWluPSJDbGlwcGVkIFJlYWQgTGVuZ3RoIikKIyBhYyA8LSBhbHBoYWJldEJ5Q3ljbGUoc3JlYWQoc2ZmKSxhbHBoYWJldD1jKCJBIiwiQyIsIlQiLCJHIiwiTiIpKQojIGFjLnJlYWRzIDwtIGFwcGx5KGFjLDIsc3VtKQojIGFjZiA8LSBzd2VlcChhYyxNQVJHSU49MixGVU49Ii8iLFNUQVRTPWFwcGx5KGFjLDIsc3VtKSkKIyBtYXRwbG90KGNiaW5kKHQoYWNmKSxhYy5yZWFkcy9hYy5yZWFkc1sxXSksY29sPWMoImdyZWVuIiwiYmx1ZSIsImJsYWNrIiwicmVkIiwiZGFya2dyZXkiLCJwdXJwbGUiKSwKIyAgICAgICAgIHR5cGU9ImwiLGx0eT0xLHhsYWI9IkJhc2UgUG9zaXRpb24iLHlsYWI9IkJhc2UgRnJlcXVlbmN5IiwKIyAgICAgICAgIG1haW49IkJhc2UgYnkgcG9zaXRpb24iKQojIGxlZ2VuZCgidG9wcmlnaHQiLCBjb2w9Y29scywgbGVnZW5kPWxlZywgcGNoPTE4LCBjZXg9LjgpCgpgYGAKCgoKCiMjIyMgSU1QT1JUIERBVEEKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyBTSU4gQ0xJUCAtIFJBVyBEQVRBIEFOQUxZU0lTCgpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCgpsZW5TdGF0X3JhdzwtdmVjdG9yKCkKbGVuU3RhdF9xdWFsPC12ZWN0b3IoKQpudWNGcmVxX3JhdzwtbWF0cml4KG5yb3c9MTAwMCwgbmNvbD0xKQpudWNGcmVxX3F1YWw8LW1hdHJpeChucm93PTEwMDAsIG5jb2w9MSkKCmNvdW50X3JhdzwtZGF0YS5mcmFtZSgpCmNvdW50X3F1YWw8LWRhdGEuZnJhbWUoKQpsZW5fcmF3PC1saXN0KCkKbGVuX3F1YWw8LWxpc3QoKQoKCmZvcihpIGluIHNhbXBsZXMpewogIHNmZjwtcmVhZFNmZihwYXN0ZSgic2FtcGxlcy8iLGksc2VwPSIiKSwgdXNlLnF1YWxpdGllcz1UUlVFLCB1c2UubmFtZXM9VFJVRSxjbGlwTW9kZSA9IGMoInJhdyIpLCB2ZXJib3NlPVRSVUUpCiMjR2VuZXJhdGUgc29tZSBRQSBwbG90czoKICAjI1JlYWQgbGVuZ3RoIGhpc3RvZ3JhbXMgKHdpdGggYW5kIHdpdGhvdXQgY2xpcHBpbmcpOgogIAogICMgUkFXCiAgcGFyKG1mcm93PWMoMiwyKSkKICBjbGlwTW9kZShzZmYpIDwtICJyYXciCiAgaGlzdCh3aWR0aChzZmYpLGJyZWFrcz01MDAsY29sPSJncmV5Iix4bGFiPSJSZWFkIExlbmd0aCIsCiAgICAgICB4bGltPSBjKDUwLDgwMCksIG1haW49ICJSQVcgcmVhZCBsZW5ndGgiKQogIGxlblN0YXRfcmF3PC1yYmluZChsZW5TdGF0X3JhdywgYyhnc3ViKCI0NTRSZWFkcy5NSURfIiwiIixnc3ViKCIuc2ZmIiwiIixpKSksIHN1bW1hcnkod2lkdGgoc2ZmKSkgKSApCiAgY291bnRfcmF3W2ksMV08LWxlbmd0aChzZmYpCiAgbGVuX3Jhd1tbaV1dPC13aWR0aChzZmYpCiAgICAjIyBCYXNlIGJ5IHBvc2l0aW9uIHBsb3RzOgogIGFjIDwtIGFscGhhYmV0QnlDeWNsZShzcmVhZChzZmYpLGFscGhhYmV0PWMoIkEiLCJDIiwiVCIsIkciLCJOIikpCiAgYWMucmVhZHMgPC0gYXBwbHkoYWMsMixzdW0pCiAgYWNmIDwtIHN3ZWVwKGFjLE1BUkdJTj0yLEZVTj0iLyIsU1RBVFM9YXBwbHkoYWMsMixzdW0pKQogIHRhY2Y8LXQoYWNmKTsgY29sbmFtZXModGFjZik8LXBhc3RlKGdzdWIoIjQ1NFJlYWRzLk1JRF8iLCIiLGdzdWIoIi5zZmYiLCIiLGkpKSwiXyIsICBjKCJBIiwiQyIsIlQiLCJHIiwiTiIpLHNlcD0iIikKICBudWNGcmVxX3JhdzwtY2JpbmRYKG51Y0ZyZXFfcmF3LHRhY2YpCiAgbWF0cGxvdChjYmluZCh0KGFjZiksYWMucmVhZHMvYWMucmVhZHNbMV0pLGNvbD1jKCJncmVlbiIsImJsdWUiLCJibGFjayIsInJlZCIsImRhcmtncmV5IiwicHVycGxlIiksCiAgICAgICAgdHlwZT0ibCIsbHR5PTEseGxhYj0iQmFzZSBQb3NpdGlvbiIseWxhYj0iQmFzZSBGcmVxdWVuY3kiLAogICAgICAgIG1haW49IkJhc2UgYnkgcG9zaXRpb24iLCB4bGltPWMoMCwxNTAwKSkKICBjb2xzIDwtIGMoImdyZWVuIiwiYmx1ZSIsImJsYWNrIiwicmVkIiwiZGFya2dyZXkiLCJwdXJwbGUiKQogIGxlZyA8LSBjKCJBIiwiQyIsIlQiLCJHIiwiTiIsIiVyZWFkcyIpCiAgbGVnZW5kKCJ0b3ByaWdodCIsIGNvbD1jb2xzLCBsZWdlbmQ9bGVnLCBwY2g9MTgsIGNleD0uOCkKICAKICAjIyMgRklMVEVSIFFVQUxJVFkKICBjbGlwTW9kZShzZmYpIDwtICJmdWxsIgogIGhpc3Qod2lkdGgoc2ZmKSxicmVha3M9NTAwLGNvbD0iZ3JleSIseGxhYj0iUmVhZCBMZW5ndGgiLAogICAgICAgeGxpbT0gYyg1MCw4MDApLG1haW49IkNMSVBQRUQgcmVhZCBsZW5ndGgiICkKICBsZW5TdGF0X3F1YWw8LXJiaW5kKGxlblN0YXRfcXVhbCxjKGdzdWIoIjQ1NFJlYWRzLk1JRF8iLCIiLGdzdWIoIi5zZmYiLCIiLGkpKSwgc3VtbWFyeSh3aWR0aChzZmYpKSApICkKICBjb3VudF9xdWFsW2ksMV08LWxlbmd0aChzZmYpCiAgbGVuX3F1YWxbW2ldXTwtd2lkdGgoc2ZmKQogICMjIEJhc2UgYnkgcG9zaXRpb24gcGxvdHM6CiAgYWMgPC0gYWxwaGFiZXRCeUN5Y2xlKHNyZWFkKHNmZiksYWxwaGFiZXQ9YygiQSIsIkMiLCJUIiwiRyIsIk4iKSkKICBhYy5yZWFkcyA8LSBhcHBseShhYywyLHN1bSkKICBhY2YgPC0gc3dlZXAoYWMsTUFSR0lOPTIsRlVOPSIvIixTVEFUUz1hcHBseShhYywyLHN1bSkpCiAgICB0YWNmPC10KGFjZik7IGNvbG5hbWVzKHRhY2YpPC1wYXN0ZShnc3ViKCI0NTRSZWFkcy5NSURfIiwiIixnc3ViKCIuc2ZmIiwiIixpKSksIl8iLCAgYygiQSIsIkMiLCJUIiwiRyIsIk4iKSxzZXA9IiIpCiAgbnVjRnJlcV9xdWFsPC1jYmluZFgobnVjRnJlcV9xdWFsLHRhY2YpCiAgbWF0cGxvdChjYmluZCh0KGFjZiksYWMucmVhZHMvYWMucmVhZHNbMV0pLGNvbD1jKCJncmVlbiIsImJsdWUiLCJibGFjayIsInJlZCIsImRhcmtncmV5IiwicHVycGxlIiksCiAgICAgICAgdHlwZT0ibCIsbHR5PTEseGxhYj0iQmFzZSBQb3NpdGlvbiIseWxhYj0iQmFzZSBGcmVxdWVuY3kiLAogICAgICAgIG1haW49IkJhc2UgYnkgcG9zaXRpb24iLCB4bGltPWMoMCwxMDAwKSkKICBwYXIobWZyb3c9YygxLDEpKQogIGxlZ2VuZCgidG9wcmlnaHQiLCBjb2w9Y29scywgbGVnZW5kPWxlZywgcGNoPTE4LCBjZXg9LjgpCiAgdGl0bGUocGFzdGUoInNhbXBsZTogIixnc3ViKCI0NTRSZWFkcy5NSURfIiwiIixnc3ViKCIuc2ZmIiwiIixpKSksc2VwPSIiKSkKICBkZXYuY29weShwbmcsZmlsZW5hbWU9cGFzdGUoIkV4cGxvXyIsZ3N1YigiNDU0UmVhZHMuTUlEXyIsIiIsZ3N1YigiLnNmZiIsIiIsaSkpLCIucG5nIixzZXA9IiIpKTsKICBkZXYub2ZmICgpOwp9CgoKYGBgCgoKCgoKIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIwojIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjCiMjIyMgRXN0YWTDrXN0aWNhcyBkZSBsYXMgbGVjdHVyYXMKYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNTdGF0aXN0aWNzIGFib3V0IGxlbmdodAphcy5kYXRhLmZyYW1lKGxlblN0YXRfcmF3KQp3cml0ZS5jc3YoYXMuZGF0YS5mcmFtZShsZW5TdGF0X3JhdyksICJSYXdfUmVhZGxlbmd0aF9zdGF0cy5jc3YiLHJvdy5uYW1lcyA9IEZBTFNFICkKYXMuZGF0YS5mcmFtZShsZW5TdGF0X3F1YWwpCndyaXRlLmNzdihhcy5kYXRhLmZyYW1lKGxlblN0YXRfcXVhbCksICJDbGlwX1JlYWRsZW5ndGhfc3RhdHMuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCgojTnVjbGVvdGlkZSBmcmVxdWVuY3kgYnkgcG9zaXRpb24Kd3JpdGUuY3N2KG51Y0ZyZXFfcmF3LCAiUmF3X051Y2xGcmVxQnlQb3MuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCndyaXRlLmNzdihudWNGcmVxX3F1YWwsICJDbGlwX051Y2xGcmVxQnlQb3MuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCgojQWxsIGxlbmd0aCBkYXRhIGJ5IHNhbXBsZQpjb3VudF9yYXckc2FtcGxlPC1nc3ViKCI0NTRSZWFkcy5NSURfIiwiIixnc3ViKCIuc2ZmIiwiIixyb3duYW1lcyhjb3VudF9yYXcpKSkKY291bnRfcXVhbCRzYW1wbGU8LWdzdWIoIjQ1NFJlYWRzLk1JRF8iLCIiLGdzdWIoIi5zZmYiLCIiLHJvd25hbWVzKGNvdW50X3F1YWwpKSkKbGVuZ3RoX3JhdzwtZG8uY2FsbChjYmluZFgsIGxhcHBseShsZW5fcmF3LCBhcy5kYXRhLmZyYW1lKSkKY29sbmFtZXMobGVuZ3RoX3Jhdyk8LWdzdWIoIjQ1NFJlYWRzLk1JRF8iLCIiLGdzdWIoIi5zZmYiLCIiLHJvd25hbWVzKGNvdW50X3JhdykpKQpsZW5ndGhfcXVhbDwtZG8uY2FsbChjYmluZFgsIGxhcHBseShsZW5fcXVhbCwgYXMuZGF0YS5mcmFtZSkpCmNvbG5hbWVzKGxlbmd0aF9xdWFsKTwtZ3N1YigiNDU0UmVhZHMuTUlEXyIsIiIsZ3N1YigiLnNmZiIsIiIscm93bmFtZXMoY291bnRfcXVhbCkpKQpyb3duYW1lcyhjb3VudF9yYXcpPC1OVUxMO3Jvd25hbWVzKGNvdW50X3F1YWwpPC1OVUxMCgoKd3JpdGUuY3N2KGxlbmd0aF9yYXcsICJSYXdfQWxsUmVhZGxlbmd0aC5jc3YiLHJvdy5uYW1lcyA9IEZBTFNFICkKd3JpdGUuY3N2KGxlbmd0aF9xdWFsLCAiQ2xpcF9BbGxSZWFkbGVuZ3RoLmNzdiIscm93Lm5hbWVzID0gRkFMU0UgKQoKI0FNb3VudCBvZiBzZXF1ZW5jZXMgYnkgc2FtcGxlCmNvdW50X3Jhdwp3cml0ZS5jc3YoY291bnRfcmF3LCAiUmF3X0NvdW50QnlTYW1wbGUuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCmNvdW50X3F1YWwKd3JpdGUuY3N2KGNvdW50X3F1YWwsICJDbGlwX0NvdW50QnlTYW1wbGUuY3N2Iixyb3cubmFtZXMgPSBGQUxTRSApCgoKYGBgCgpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI0dSQUZJQ08gREUgQkFSUkFTIENPTiBMQSBDQU5USURBRCBERSBMRUNUVVJBUwojcGxvdChjYW50aWRhZCRjYW50aWRhZCwgdHlwZT0iYiIpCmxpYnJhcnkoZ2dwbG90MikKcDwtZ2dwbG90KGNvdW50X3JhdywgYWVzKHg9c2FtcGxlLCB3ZWlnaHQ9VjEpKSsgZ2VvbV9iYXIoZmlsbD0iIzJiOGNiZSIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpCmdncGxvdGx5KHApCmBgYAoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojR1JBRklDTyBERSBDQUpBUwojYm94cGxvdChsb25naXR1ZCkKcDwtZ2dwbG90KGRhdGEgPSBtZWx0KGxlbmd0aF9yYXcpLCBhZXMoeD12YXJpYWJsZSwgeT12YWx1ZSkpICsgZ2VvbV9ib3hwbG90KGFlcyhmaWxsPXZhcmlhYmxlKSkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkrIGdndGl0bGUoIlJhdyBSZWFkcyIpCmdncGxvdGx5KHApCmBgYAoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojR1JBRklDTyBERSBDQUpBUwojYm94cGxvdChsb25naXR1ZCkKcDwtZ2dwbG90KGRhdGEgPSBtZWx0KGxlbmd0aF9xdWFsKSwgYWVzKHg9dmFyaWFibGUsIHk9dmFsdWUpKSArIGdlb21fYm94cGxvdChhZXMoZmlsbD12YXJpYWJsZSkpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpKyBnZ3RpdGxlKCJDbGlwcGVkIFJlYWRzIikKZ2dwbG90bHkocCkKYGBgCgpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KZm9yKGkgaW4gc2FtcGxlcyl7CiAgc2ZmPC1yZWFkU2ZmKHBhc3RlKCJzYW1wbGVzLyIsaSxzZXA9IiIpLCB1c2UucXVhbGl0aWVzPVRSVUUsIHVzZS5uYW1lcz1UUlVFLGNsaXBNb2RlID0gYygicmF3IiksIHZlcmJvc2U9VFJVRSkKY3VzdG9tQ2xpcChzZmYpIDwtIElSYW5nZXMoc3RhcnQgPSAxLCBlbmQgPSAxNSkKY2xpcE1vZGUoc2ZmKSA8LSAiY3VzdG9tIgpwcmludCgiZGlzdGluY3QgTUlEcyBhdCA1JyIpCnByaW50KGxlbmd0aCh0YWJsZShjb3VudHM9YXMuY2hhcmFjdGVyKHNyZWFkKHNmZikpKSkpCnByaW50KCJNb3JlIGZyZXF1ZW50cyIpCnByaW50KHNvcnQodGFibGUoY291bnRzPWFzLmNoYXJhY3RlcihzcmVhZChzZmYpKSksIGRlY3JlYXNpbmc9VFJVRSkpCn0KYGBgCgoKIyMjIEV4cGxvcmUgRWFjaCBzZXF1ZQpgYGB7ciAgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KaT1zYW1wbGVzWzFdCiAgc2ZmPC1yZWFkU2ZmKHBhc3RlKCJzYW1wbGVzLyIsaSxzZXA9IiIpLCB1c2UucXVhbGl0aWVzPVRSVUUsIHVzZS5uYW1lcz1UUlVFLGNsaXBNb2RlID0gYygicmF3IiksIHZlcmJvc2U9VFJVRSkKCnJlYWRzUmF3PC1zcmVhZChzZmYpCnJlYWRzUmF3V2lkdGg8LWFzLmRhdGEuZnJhbWUoY2JpbmQobmFtZXMocmVhZHNSYXcpLHdpZHRoKHJlYWRzUmF3KSkpCmhlYWQocmVhZHNSYXdXaWR0aCkKcmVhZFJhd1M8LXJlYWRzUmF3WzFdCm5hbWVzKHJlYWRSYXdTKTwtcGFzdGUobmFtZXMocmVhZFJhd1MpLCJfcmF3IixzZXA9IiIpCnJlYWRSYXdRPC1xdWFsaXR5KHNmZilbMV0Kd3JpdGVYU3RyaW5nU2V0KHJlYWRSYXdTLCBmaWxlPSJyZWFkUmF3Uy5mYXN0YSIsIGZvcm1hdD0iZmFzdGEiKSAKY2xpcE1vZGUoc2ZmKSA8LSAicmF3IgoKI0FmdGVyIHF1YWxsaXR5IGNsaXAoIHNpbWlsYXIgdG8gcm9jaGUgY2xpcCBtb2RlKQpjbGlwTW9kZShzZmYpIDwtICJmdWxsIgpyZWFkc0Z1bGw8LXNyZWFkKHNmZikKcmVhZHNGdWxsV2lkdGg8LWFzLmRhdGEuZnJhbWUoY2JpbmQobmFtZXMocmVhZHNGdWxsKSx3aWR0aChyZWFkc0Z1bGwpKSkKaGVhZChyZWFkc0Z1bGxXaWR0aCkKbmFtZXMocmVhZEZ1bGxTKTwtcGFzdGUobmFtZXMocmVhZEZ1bGxTKSwiX2Z1bGwiLHNlcD0iIikKcmVhZEZ1bGxRPC1xdWFsaXR5KHNmZilbMV0Kd3JpdGVYU3RyaW5nU2V0KHJlYWRGdWxsUywgZmlsZT0icmVhZEZ1bGxTLmZhc3RhIiwgZm9ybWF0PSJmYXN0YSIpIAoKcXVhbnRpbGUoYXMocmVhZEZ1bGxRLCAibnVtZXJpYyIpKQoKY2hlY2t0YWI8LWFzLmRhdGEuZnJhbWUoIAogICAgICAgICAgY2JpbmRYKCAKICAgICAgICAgICAgYXMubWF0cml4KGFzLm1hdHJpeChyZWFkUmF3UylbMTU6bGVuZ3RoKGFzLm1hdHJpeChyZWFkUmF3UykpXSApICwKICAgICAgICAgICAgICBhcy5tYXRyaXgoIChhcy5udW1lcmljKHJlYWRSYXdRW1sxXV0pLTMzKVsxNDpsZW5ndGgoYXMubnVtZXJpYyhyZWFkUmF3UVtbMV1dKS0zMyldKSwgCiAgICAgICAgICAgICAgICAgIHQoYXMubWF0cml4KHJlYWRGdWxsUykpICwKICAgICAgICAgICAgICAgICAgICBhcy5tYXRyaXgoIChhcy5udW1lcmljKHJlYWRGdWxsUVtbMV1dKS0zMylbMTQ6bGVuZ3RoKGFzLm51bWVyaWMocmVhZEZ1bGxRW1sxXV0pLTMzKV0pICApKSAgCndyaXRlLmNzdihjaGVja3RhYiwgImNoZWNrdGFiLmNzdiIsIHJvdy5uYW1lcyA9IEZBTFNFKQoKCgpgYGAKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpyZWFkc1Jhdzwtc3JlYWQoc2ZmKQpyZWFkc1Jhd1E8LSAgIGFzKHF1YWxpdHkoc2ZmKSwgIlBocmVkUXVhbGl0eSIpICAKbGlicmFyeShTaG9ydFJlYWQpOyBzZXRTUiA8LSBTaG9ydFJlYWRRKHNyZWFkPXJlYWRzUmF3LCBxdWFsaXR5PUZhc3RxUXVhbGl0eShCU3RyaW5nU2V0KHJlYWRzUmF3USkpLCBCU3RyaW5nU2V0KHJlYWRzUmF3USkpCm15TUEgPC0gYXMocXVhbGl0eShzZXRTUiksICJtYXRyaXgiKQpgYGAKCiMjIyBQcm9jZXNzZWQgd2l0aCBTU0ZpbmZvCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpmaWxlX25hbWU8LWdzdWIoIjQ1NFJlYWRzLk1JRF8iLCIiLGdzdWIoIi5zZmYiLCIiLGkpKQoKbGlicmFyeShCaW9zdHJpbmdzKQpwcm8xX3JlYWQgPSByZWFkRE5BU3RyaW5nU2V0KHBhc3RlKCJzYW1wbGVzL3Byb2Nlc3NlZF9maWxlcy8iLGZpbGVfbmFtZSwiLyIsZmlsZV9uYW1lLCIuZm5hIiwgc2VwPSIiKSwgZm9ybWF0PSJmYXN0YSIpCnBybzFfcmVhZF93aWR0aDwtYXMuZGF0YS5mcmFtZShjYmluZChuYW1lcyhwcm8xX3JlYWQpLHdpZHRoKHBybzFfcmVhZCkpKQpoZWFkKHBybzFfcmVhZF93aWR0aCkKYGBgCgoKYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgpzZmZDb250YWluZXIgPC0gcmVhZFNGRihwYXN0ZSgic2FtcGxlcy8iLGksc2VwPSIiKSkKc2hvd0NsYXNzKCJTRkZDb250YWluZXIiKQpyZWFkcyhzZmZDb250YWluZXIpCiNxdWFsaXR5UmVwb3J0U0ZGKHNmZkNvbnRhaW5lciwgInJlcG9ydC5wZGYiKQpwb3NpdGlvblF1YWxpdHlCb3hwbG90KHNmZkNvbnRhaW5lcikKI2RpbnVjbGVvdGlkZU9kZHNSYXRpbwojc2ZmMmZhc3RxKCkKYGBgCgoKYGBge3IgIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNFeGFtcGxlIGZsb3dncmFtCnkgYwpjb2xuYW1lcyhzZXF0YWIpPC1jKCJmbG93Z3JhbXMiLCJmbG93SW5kZXhlcyIsImJhc2VjYWxsIiwicXVhbGl0eV9jaGFyIiwicXVhbGl0eV92YWx1ZSIpCnNlcXRhYiU+JQogIGdyb3VwX2J5KGJhc2VjYWxsKSU+JQogICAgICAgIHBsb3RfbHkoIHkgPSB+cXVhbGl0eV92YWx1ZSwgY29sb3IgPSB+YmFzZWNhbGwsIHR5cGUgPSAiYm94IikKYGBgCgoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpzZXF0YWIlPiUKICBncm91cF9ieShiYXNlY2FsbCklPiUKICAgICAgICBwbG90X2x5KCB5ID0gfmZsb3dncmFtcywgY29sb3IgPSB+YmFzZWNhbGwsIHR5cGUgPSAiYm94IikKICAKICAgICAKYGBgCgoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojc2ZmQ29udGFpbmVyQGNsaXBRdWFsaXR5TGVmdAojc2ZmQ29udGFpbmVyQGNsaXBRdWFsaXR5UmlnaHQKCgojIyMKI2NvbnZlcnQgaHR0cDovL3d3dy5kcml2ZTUuY29tL3VzZWFyY2gvbWFudWFsL3F1YWxpdHlfc2NvcmUuaHRtbAojaHR0cDovL2dhdGtmb3J1bXMuYnJvYWRpbnN0aXR1dGUub3JnL2dhdGsvZGlzY3Vzc2lvbi80MjYwL3BocmVkLXNjYWxlZC1xdWFsaXR5LXNjb3JlcwoKI2FzLm51bWVyaWMoc2ZmQ29udGFpbmVyQHJlYWRzQHF1YWxpdHkkSDNDOEhYWDAxQVRHMFMpCmBgYAoKCmBgYHtyICBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIyMjIEhhY2VyIHVuYSAgdmVjdG9yIHBhcmEgY2FkYSBzZWN1ZW5jaWEgY29uIHRvZGFzIGxhcyBmcmVjdWVuY2lhcyBkZSA0IG51Y2xlw7N0aWRvcwoKcmVhZHMgPSBzcmVhZChzZmYpCm5mID0gb2xpZ29udWNsZW90aWRlRnJlcXVlbmN5KHJlYWRzLCB3aWR0aD00KQojaGNsdXN0KGRpc3QobmYpKSAjIGRvIGhpZXJhcmNoaWNhbCBjbHVzdGVyaW5nIG9mIHlvdXIgdGV0cmEgZnJlcS4KCmBgYAo=